/******************************************************************************
 * * nv_api.c - implementation of nvram interface
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/
#include "ui_nvm.h"
#include "../../../lvgl/hal/hal.h"

/**
 * get section length from section id
 * param (in) SectionId:   UI_NV_SECTION_ID  section ID of NVM
 * return  uint32_t:
 */
uint32_t UI_NV_Get_Section_Len(NV_UI_SECTION_ID SectionId)
{
    switch(SectionId) {
        case NV_SECTION_UI_SETTINGS:
            return(NV_SECTION_LEN(NV_SECTION_UI_SETTINGS));

        case NV_SECTION_UI_PHONE:
            return(NV_SECTION_LEN(NV_SECTION_UI_PHONE));

        case NV_SECTION_UI_PEDOMETER:
            return(NV_SECTION_LEN(NV_SECTION_UI_PEDOMETER));

        case NV_SECTION_UI_LAUNCHER:
            return(NV_SECTION_LEN(NV_SECTION_UI_LAUNCHER));

        case NV_SECTION_UI_PHONEBOOK:
            return(NV_SECTION_LEN(NV_SECTION_UI_PHONEBOOK));

        case NV_SECTION_UI_FACTORYMODE:
            return(NV_SECTION_LEN(NV_SECTION_UI_FACTORYMODE));

        case NV_SECTION_UI_ALARM:
            return(NV_SECTION_LEN(NV_SECTION_UI_ALARM));

        case NV_SECTION_UI_VOICE_MSG:
            return(NV_SECTION_LEN(NV_SECTION_UI_VOICE_MSG));

        case NV_SECTION_UI_ENGINEER_MODE:
            return(NV_SECTION_LEN(NV_SECTION_UI_ENGINEER_MODE));

        case NV_SECTION_UI_BLUETOOTH:
            return (NV_SECTION_LEN(NV_SECTION_UI_BLUETOOTH));

        case NV_SECTION_UI_AUDIO_PLAYER:
            return (NV_SECTION_LEN(NV_SECTION_UI_AUDIO_PLAYER));

        case NV_SECTION_UI_DM:
            return (NV_SECTION_LEN(NV_SECTION_UI_DM));

        case NV_SECTION_UI_CALL_LOG:
            return (NV_SECTION_LEN(NV_SECTION_UI_CALL_LOG));

        default:
            printf("SectionId wrong\n");
            return(0);
    } /* switch */
}     /* UI_NV_Get_Section_Len */

/**
 * get file path of section
 * param (in) SectionId:   UI_NV_SECTION_ID  section ID of NVM
 * return  int8_t*: file path
 */
char * UI_NV_Get_Section_path(NV_UI_SECTION_ID SectionId)
{
    switch(SectionId) {
        case NV_SECTION_UI_SETTINGS:
            return(NV_SECTION_FILE_PATH(NV_SECTION_UI_SETTINGS));

        case NV_SECTION_UI_PHONE:
            return(NV_SECTION_FILE_PATH(NV_SECTION_UI_PHONE));

        case NV_SECTION_UI_PEDOMETER:
            return(NV_SECTION_FILE_PATH(NV_SECTION_UI_PEDOMETER));

        case NV_SECTION_UI_LAUNCHER:
            return(NV_SECTION_FILE_PATH(NV_SECTION_UI_LAUNCHER));

        case NV_SECTION_UI_PHONEBOOK:
            return(NV_SECTION_FILE_PATH(NV_SECTION_UI_PHONEBOOK));

        case NV_SECTION_UI_FACTORYMODE:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_FACTORYMODE));

        case NV_SECTION_UI_ALARM:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_ALARM));

        case NV_SECTION_UI_VOICE_MSG:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_VOICE_MSG));

        case NV_SECTION_UI_ENGINEER_MODE:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_ENGINEER_MODE));

        case NV_SECTION_UI_BLUETOOTH:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_BLUETOOTH));

        case NV_SECTION_UI_AUDIO_PLAYER:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_AUDIO_PLAYER));

        case NV_SECTION_UI_DM:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_DM));

        case NV_SECTION_UI_CALL_LOG:
            return (NV_SECTION_FILE_PATH(NV_SECTION_UI_CALL_LOG));

        default:
            printf("SectionId wrong\n");
            return(NULL);
    } /* switch */
}     /* UI_NV_Get_Section_Offset */

/**
 * reset nv to default value
 * param (in) SectionId:   UI_NV_SECTION_ID  section ID of NVM
 * return  uint8_t: 1 means reset done, 0 means not reset
 */
uint8_t UI_NV_Reset_Default(NV_UI_SECTION_ID SectionId)
{
    char * TempData;
    uint32_t SectionLen = UI_NV_Get_Section_Len(SectionId);
    char FilePath[NV_MAX_SECTION_PATH_NAME];
    ui_file_t * pfile;
    nv_watch_settings_t * setting;
    nv_watch_phone_t * phone;
    nv_watch_pedometer_t * pedometer;
    nv_watch_launcher_t * launcher;
    nv_watch_phonebook_t * phonebook;
    nv_watch_factorymode_t * factorymode;
    nv_watch_alarm_t * alarm;
    nv_watch_voice_msg_t * voicemsg;
    nv_watch_engineer_mode_t * engineermode;
    nv_watch_bluetooth_t * bluetooth;
    nv_watch_audio_player_t *audioplayer;
    nv_watch_dm_t * dm;
    nv_watch_call_log_t * calllog;

    switch(SectionId) {
        case NV_SECTION_UI_SETTINGS:
            setting = lv_mem_alloc(SectionLen);
            memset(setting, 0, SectionLen);

            setting->ringvolume = 8;
            setting->currentwallpaperindex = 1;
            setting->backlightintensity = 3;
            setting->backlighttimeout = 15;
            setting->currentlanguage = 1;
            setting->timesetflg = 0;
            setting->simid = 0;
            setting->mobiledataswitch = 255; // invalid value
            setting->searchswitch = 0;
            setting->flyingmodeswitch = 0;
            TempData = (char *)setting;
            break;
        case NV_SECTION_UI_PHONE:
            phone = lv_mem_alloc(SectionLen);
            memset(phone, 0, SectionLen);

            phone->volume = 10;
            phone->emergency_number.number_cnt = 10;
            //ECCLIST
            phone->emergency_number.number[0][0] = '1';
            phone->emergency_number.number[0][1] = '1';
            phone->emergency_number.number[0][2] = '2';

            phone->emergency_number.number[1][0] = '0';
            phone->emergency_number.number[1][1] = '0';
            phone->emergency_number.number[1][2] = '0';

            phone->emergency_number.number[2][0] = '0';
            phone->emergency_number.number[2][1] = '8';

            phone->emergency_number.number[3][0] = '1';
            phone->emergency_number.number[3][1] = '1';
            phone->emergency_number.number[3][2] = '8';

            phone->emergency_number.number[4][0] = '9';
            phone->emergency_number.number[4][1] = '1';
            phone->emergency_number.number[4][2] = '1';

            phone->emergency_number.number[5][0] = '9';
            phone->emergency_number.number[5][1] = '9';
            phone->emergency_number.number[5][2] = '9';

            //CEN 460
            phone->emergency_number.number[6][0] = '1';
            phone->emergency_number.number[6][1] = '1';
            phone->emergency_number.number[6][2] = '0';

            phone->emergency_number.number[7][0] = '1';
            phone->emergency_number.number[7][1] = '1';
            phone->emergency_number.number[7][2] = '9';

            phone->emergency_number.number[8][0] = '1';
            phone->emergency_number.number[8][1] = '2';
            phone->emergency_number.number[8][2] = '0';

            phone->emergency_number.number[9][0] = '1';
            phone->emergency_number.number[9][1] = '2';
            phone->emergency_number.number[9][2] = '2';

            TempData = (char *)phone;
            break;
        case NV_SECTION_UI_PEDOMETER:
            pedometer = lv_mem_alloc(SectionLen);
            memset(pedometer, 0, SectionLen);

            pedometer->pedosetting.height = 170;
            pedometer->pedosetting.weight = 60;
            pedometer->pedosetting.goal = 10000;
            TempData = (char *)pedometer;
            break;
        case NV_SECTION_UI_LAUNCHER:
            launcher = lv_mem_alloc(SectionLen);
            memset(launcher, 0, SectionLen);
            TempData = (char *)launcher;
            break;
        case NV_SECTION_UI_PHONEBOOK:
            phonebook = lv_mem_alloc(SectionLen);
            memset(phonebook, 0, SectionLen);
            TempData = (char *)phonebook;
            break;
        case NV_SECTION_UI_FACTORYMODE:
            factorymode = lv_mem_alloc(SectionLen);
            memset(factorymode, 0, SectionLen);
            TempData = (char *)factorymode;
            break;
        case NV_SECTION_UI_ALARM:
            alarm = lv_mem_alloc(SectionLen);
            memset(alarm, 0, SectionLen);
            TempData = (char *)alarm;
            break;
        case NV_SECTION_UI_VOICE_MSG:
            voicemsg = lv_mem_alloc(SectionLen);
            memset(voicemsg, 0xFF, SectionLen);
            TempData = (char *)voicemsg;
            break;
        case NV_SECTION_UI_ENGINEER_MODE:
            engineermode = lv_mem_alloc(SectionLen);
            memset(engineermode, 0, SectionLen);
            TempData = (char *)engineermode;
            break;
        case NV_SECTION_UI_BLUETOOTH:
            bluetooth = lv_mem_alloc(SectionLen);
            memset(bluetooth, 0, SectionLen);
            TempData = (char *)bluetooth;
            break;
        case NV_SECTION_UI_AUDIO_PLAYER:
            audioplayer = lv_mem_alloc(SectionLen);
            memset(audioplayer, 0, SectionLen);
            TempData = (char *)audioplayer;
            break;
        case NV_SECTION_UI_DM:
            dm = lv_mem_alloc(SectionLen);
            memset(dm, 0, SectionLen);
            TempData = (char *)dm;
            break;
    case NV_SECTION_UI_CALL_LOG:
            calllog = lv_mem_alloc(SectionLen);
            memset(calllog, 0, SectionLen);
            TempData = (char *)calllog;
            break;
        default:
            TempData = NULL;
            break;
    }

    snprintf(FilePath, NV_MAX_SECTION_PATH_NAME, "%s%s", NV_SECTION_ROOT_DIR, UI_NV_Get_Section_path(SectionId));
    UI_FILE_REMOVE(FilePath);
    pfile = UI_FILE_OPEN((const char *)FilePath, UI_FILE_WRITE_ONLY);
    UI_FILE_WRITE(pfile, TempData, SectionLen);                                                          // write to operate file
    UI_FILE_CLOSE(pfile);
    lv_mem_free(TempData);
    return (1);
}

/**
 * write to file
 * param (in) SectionId:   UI_NV_SECTION_ID  section ID of NVM
 * param (in) Offset:  uint32_t                Offset in the Section
 * param (in) Len:   uint32_t                  Length of data to read
 * param (out) Data:  uint32_t*                data buffer
 * return  uint32_t: bytes have been writen
 */
uint32_t UI_NV_Write_Req(NV_UI_SECTION_ID SectionId, uint32_t Offset, uint32_t Len, uint8_t * Data)
{
    uint32_t    WriteLen = 0;
    ui_file_t * pfile;
    uint32_t    SectionLen;
    char      FilePath[NV_MAX_SECTION_PATH_NAME];

    SectionLen = UI_NV_Get_Section_Len(SectionId);

    if(SectionLen < (Offset + Len)) {
        printf("Len of Section is %d, offset + len = %d is too big\n",
               SectionLen,
               Offset + Len);
        return(0);
    }

    // get full file path
    snprintf(FilePath, NV_MAX_SECTION_PATH_NAME, "%s%s", NV_SECTION_ROOT_DIR, UI_NV_Get_Section_path(SectionId));

    pfile = UI_FILE_OPEN((const char *)FilePath, UI_FILE_RD_APPEND);
    if(NULL == pfile->file_d) {
        printf("please check file path\n");
        UI_NV_Reset_Default(SectionId);
        return(0);
    }

    UI_FILE_SEEK(pfile, Offset);                        // write nv data
    WriteLen = UI_FILE_WRITE(pfile, Data, Len);
    if(0 == WriteLen) {
        printf("write in fs is wrong, return default valure\n");
        return(0);
    }
    UI_FILE_CLOSE(pfile);
    return(Len);
} /* UI_NV_Write_Req */

/**
 * read data from NVRAM
 * param (in) SectionId:   UI_NV_SECTION_ID  section ID of NVM
 * param (in) Offset:  uint32_t                Offset in the Section
 * param (in) len:   uint32_t                  Length of data to read
 * param (out) data:  uint32_t*                data buffer
 * return  uint32_t: bytes have been read
 */
uint32_t UI_NV_Read_Req(NV_UI_SECTION_ID SectionId, uint32_t Offset, uint32_t Len, uint8_t * Data)
{
    uint32_t    ReadLen = 0;
    ui_file_t * pfile;
    uint32_t    SectionLen = UI_NV_Get_Section_Len(SectionId);
    char      FilePath[NV_MAX_SECTION_PATH_NAME] = {0};

    if(SectionLen < (Offset + Len)) {
        printf("len of section is %d, offset + len = %d is too big\n",
               SectionLen,
               Offset + Len);
        return(ReadLen);
    }

    // get full file path
    snprintf(FilePath, NV_MAX_SECTION_PATH_NAME, "%s%s", NV_SECTION_ROOT_DIR, UI_NV_Get_Section_path(SectionId));
    pfile = UI_FILE_OPEN((const char *)FilePath, UI_FILE_RD_APPEND);
    if(NULL == pfile->file_d) {
        printf("please check file path\n");
    } else {
        UI_FILE_SEEK(pfile, Offset);                // read data
        ReadLen = UI_FILE_READ(pfile, Data, Len);
        UI_FILE_CLOSE(pfile);
    }

    if(0 == ReadLen) {
        printf("read in fs is wrong return default value\n");
        if(1 == UI_NV_Reset_Default(SectionId)) {
            pfile = UI_FILE_OPEN((const char *)FilePath, UI_FILE_RD_APPEND);
            if(NULL == pfile->file_d) {
                printf("please check file path\n");
                return(0);
            }

            UI_FILE_SEEK(pfile, Offset);                // read data
            ReadLen = UI_FILE_READ(pfile, Data, Len);
            UI_FILE_CLOSE(pfile);
        }
    }
    return(Len);
} /* UI_NV_Read_Req */

/**
 * write default value to NVRAM for factory restore
 * return  void:
 */
void UI_NV_Restroe_Req(void)
{
    uint8_t i;
    ui_file_t * pfile;
    char      FilePath[NV_MAX_SECTION_PATH_NAME];
    // read default nvm file
    for(i = 0; i < NV_SECTION_UI_MAX_NUM; i++) {
        // section before this has default value,open default nv file
        snprintf(FilePath, NV_MAX_SECTION_PATH_NAME, "%s%s", NV_SECTION_ROOT_DIR, UI_NV_Get_Section_path(i));
        pfile = UI_FILE_OPEN((const char *)FilePath, UI_FILE_READ_ONLY);
        if(NULL == pfile->file_d) {
            UI_NV_Reset_Default(i);
        }
        UI_FILE_CLOSE(pfile);
    }
}
